﻿using System;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;

namespace NMA.Web.Core.CriteriaExpression.Category
{
    using NMA.Web.Areas.Admin.Models.SearchCriteria;
    using NMA.Infrastructure.DBC;

    public class SearchCategoryCriteriaExpression : CriteriaExpressionBase<CategorySearchCriteria, SearchCategoryCriteriaType>
    {
        [Obsolete("This function is not used")]
        public override Expression<Func<CategorySearchCriteria, bool>> CreatedCriteriaExpression(CategorySearchCriteria criteriaModel, SearchCategoryCriteriaType criteriaType)
        {
            Check.Assert(criteriaModel != null, "CategorySearchCriteria is null");

            Expression<Func<CategorySearchCriteria, bool>> result = null;
            // build global x param, if not build it we have a not global x parametter when execute Lambda Expression
            ParameterExpression paramX = Expression.Parameter(typeof(CategorySearchCriteria), "x");
            Tuple<ParameterExpression, CategorySearchCriteria> parametters = new Tuple<ParameterExpression, CategorySearchCriteria>(paramX, criteriaModel);

            switch (criteriaType)
            {
                case SearchCategoryCriteriaType.Id:
                    break;
                case SearchCategoryCriteriaType.Name:
                    result = GetNameExpression(parametters);
                    break;
                case SearchCategoryCriteriaType.CreatedUser:
                    break;
                case SearchCategoryCriteriaType.CreatedDate:
                    break;
                case SearchCategoryCriteriaType.IdAndName:
                    result = GetIdAndNameExpression(parametters);
                    break;
                case SearchCategoryCriteriaType.IdAndCreatedUser:
                    break;
                case SearchCategoryCriteriaType.IdAndCreatedDate:
                    break;
                case SearchCategoryCriteriaType.NameAndCreatedUser:
                    break;
                case SearchCategoryCriteriaType.NameAndCreatedDate:
                    break;
                case SearchCategoryCriteriaType.CreatedUserAndCreatedDate:
                    break;
                case SearchCategoryCriteriaType.IdAndNameAndCreatedUser:
                    break;
                case SearchCategoryCriteriaType.IdAndNameAndCreatedDate:
                    break;
                case SearchCategoryCriteriaType.NameAndCreatedUserAndCreatedDate:
                    break;
                case SearchCategoryCriteriaType.IdAndNameAndCreatedUserAndCreatedDate:
                    break;
                default:
                    break;
            }

            return result;
        }

        #region private functions

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> GetIdExpression(Tuple<ParameterExpression, CategorySearchCriteria> parametters)
        {
            Tuple<BinaryExpression, ParameterExpression> result = GetIdExpressionHelper(parametters.Item1, parametters.Item2.Id);

            if (result == null)
                throw new Exception("Tuple<BinaryExpression, ParameterExpression> object is null");

            return BuildLambdaExpression(result);
        }

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> GetNameExpression(Tuple<ParameterExpression, CategorySearchCriteria> parametters)
        {
            Tuple<BinaryExpression, ParameterExpression> result = GetNameExpressionHelper(parametters.Item1, parametters.Item2.Name);

            if (result == null)
                throw new Exception("Tuple<BinaryExpression, ParameterExpression> object is null");

            return BuildLambdaExpression(result);
        }

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> GetCreatedByExpression(Tuple<ParameterExpression, CategorySearchCriteria> parametters)
        {
            Tuple<BinaryExpression, ParameterExpression> result = GetCreatedByExpressionHelper(parametters.Item1, parametters.Item2.CreatedUser);

            if (result == null)
                throw new Exception("Tuple<BinaryExpression, ParameterExpression> object is null");

            return BuildLambdaExpression(result);
        }

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> GetCreatedDateExpression(Tuple<ParameterExpression, CategorySearchCriteria> parametters)
        {
            Tuple<BinaryExpression, ParameterExpression> result = GetCreatedDateExpressionHelper(parametters.Item1, parametters.Item2.CreatedDate);

            if (result == null)
                throw new Exception("Tuple<BinaryExpression, ParameterExpression> object is null");

            return BuildLambdaExpression(result);
        }

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> GetIdAndNameExpression(Tuple<ParameterExpression, CategorySearchCriteria> parametters)
        {
            Tuple<BinaryExpression, ParameterExpression> idResult = GetIdExpressionHelper(parametters.Item1, parametters.Item2.Id);
            Tuple<BinaryExpression, ParameterExpression> nameResult = GetNameExpressionHelper(parametters.Item1, parametters.Item2.Name);

            if (idResult == null || nameResult == null)
                throw new Exception("Tuple<BinaryExpression, ParameterExpression> object is null");

            var idAndNameExpr = Expression.And(idResult.Item1, nameResult.Item1);

            // anyway, we can use Item2 in idResult or nameResult
            Tuple<BinaryExpression, ParameterExpression> idAndNameTuple = new Tuple<BinaryExpression, ParameterExpression>(idAndNameExpr, idResult.Item2);

            return BuildLambdaExpression(idAndNameTuple);
        }

        #endregion

        #region helper functions

        [Obsolete("This function is not used")]
        private Expression<Func<CategorySearchCriteria, bool>> BuildLambdaExpression(Tuple<BinaryExpression, ParameterExpression> parametters)
        {
            Check.Assert(parametters != null, "Tuple<BinaryExpression, ParameterExpression> object is null");

            return Expression.Lambda<Func<CategorySearchCriteria, bool>>(parametters.Item1, new ParameterExpression[] { parametters.Item2 });
        }

        [Obsolete("This function is not used")]
        private Tuple<BinaryExpression, ParameterExpression> GetIdExpressionHelper(ParameterExpression paramX, Guid id)
        {
            // x.Name
            MemberExpression memberXName = Expression.Property(paramX, typeof(CategorySearchCriteria).GetProperty("Name"));

            // constant, for example: "abc"
            ConstantExpression paramConstant = Expression.Constant("testName");
            ConstantExpression paramZeroConstant = Expression.Constant(0);

            ParameterExpression paramString = Expression.Parameter(typeof(String), "String");

            // get string.Compare method from string
            var methods = typeof(String).GetMethods().Where(x => x.Name.Equals("Compare"));

            MethodInfo methodInfo = methods.FirstOrDefault();

            var methodCall = Expression.Call(null, methodInfo, memberXName, paramConstant);

            // for example: a == b
            BinaryExpression binaryEx = Expression.Equal(methodCall, paramZeroConstant);

            return new Tuple<BinaryExpression, ParameterExpression>(binaryEx, paramX);
            //return null;
        }

        [Obsolete("This function is not used")]
        private Tuple<BinaryExpression, ParameterExpression> GetNameExpressionHelper(ParameterExpression paramX, string name)
        {
            // x.Name
            MemberExpression memberXName = Expression.Property(paramX, typeof(CategorySearchCriteria).GetProperty("Name"));

            // constant, for example: "abc"
            ConstantExpression paramConstant = Expression.Constant(name);
            ConstantExpression paramZeroConstant = Expression.Constant(0);

            ParameterExpression paramString = Expression.Parameter(typeof(String), "String");

            // get string.Compare method from string
            var methods = typeof(String).GetMethods().Where(x => x.Name.Equals("Compare"));

            MethodInfo methodInfo = methods.FirstOrDefault();

            var methodCall = Expression.Call(null, methodInfo, memberXName, paramConstant);

            // for example: a == b
            BinaryExpression binaryEx = Expression.Equal(methodCall, paramZeroConstant);

            return new Tuple<BinaryExpression, ParameterExpression>(binaryEx, paramX);
        }

        [Obsolete("This function is not used")]
        private Tuple<BinaryExpression, ParameterExpression> GetCreatedByExpressionHelper(ParameterExpression paramX, string createdBy)
        {
            // x.CreatedUser
            MemberExpression memberXName = Expression.Property(paramX, typeof(CategorySearchCriteria).GetProperty("CreatedUser"));

            // constant, for example: "abc"
            ConstantExpression paramConstant = Expression.Constant(createdBy);
            ConstantExpression paramZeroConstant = Expression.Constant(0);

            ParameterExpression paramString = Expression.Parameter(typeof(String), "String");

            // get string.Compare method from string
            var methods = typeof(String).GetMethods().Where(x => x.Name.Equals("Compare"));

            MethodInfo methodInfo = methods.FirstOrDefault();

            var methodCall = Expression.Call(null, methodInfo, memberXName, paramConstant);

            // for example: a == b
            BinaryExpression binaryEx = Expression.Equal(methodCall, paramZeroConstant);

            return new Tuple<BinaryExpression, ParameterExpression>(binaryEx, paramX);
        }

        [Obsolete("This function is not used")]
        private Tuple<BinaryExpression, ParameterExpression> GetCreatedDateExpressionHelper(ParameterExpression paramX, DateTime createdDate)
        {
            return null;
        }

        #endregion
    }
}